use libloading::*;
use once_cell::sync::OnceCell;
use std::ffi::CString;
use std::os::raw::{c_char, c_int, c_ulong, c_void};
use std::path::{Path, PathBuf};
use tracing::info;
use unicode_width::UnicodeWidthStr;

use crate::lock::error_code::ERROR_CODE;
lazy_static! {
    pub static ref SOFT_DOG: OnceCell<SoftdogManager> = OnceCell::new();
}
///获取设备列表
pub type GetSn = unsafe fn(*mut c_ulong, *mut c_ulong, *mut c_ulong) -> c_ulong;
///初始化
pub type InitiateLock = unsafe fn(c_ulong) -> c_int;
///读设备
pub type ReadLock = unsafe fn(c_ulong, *mut c_void, c_ulong, *mut c_char, c_ulong) -> c_int;
///写设备
pub type WriteLock = unsafe fn(c_ulong, *mut c_void, c_ulong, *mut c_char, c_ulong) -> c_int;
///模块设置 初始化调用一次
pub type ModuleSet = unsafe fn(c_int, c_ulong) -> c_int;

pub type GetActivePsd =
    unsafe fn(*const c_char, c_ulong, c_ulong, c_ulong, c_ulong, *mut u8, c_ulong) -> c_int;

type SetLimit = unsafe fn(*mut u8, *const c_char, c_ulong, c_ulong) -> c_int;
/// 填充字符串
pub fn pad_start(s: &mut String, m: usize) {
    if let Some(columns_short) = m.checked_sub(s.width()) {
        let mut t = String::with_capacity(s.len() + columns_short);
        t.extend((0..columns_short).map(|_| '0'));
        t.push_str(s);
        *s = t;
    }
}

#[derive(Default, Debug)]
pub struct SoftdogResult {
    pub status: i32,
    pub msg: Option<String>,
    pub data: Option<String>,
}

/// 地址 1-2000(2k 空间）区域：只有
/// 相应的管理密码才可正常进行读写，读写密码不可操作。地址 2000-40000（38k 空间）区域：
/// 管理密码可以读写，读写密码只能进行读操作。地址 40000~130000 区域管理密码和读写密
/// 码都可以进行读写操作。
/// 注：动态密码如果作为密码使用，权限等同于管理密
/// 没把锁都有使用 次数 ，只要调用api 就会消耗 次数（初始化锁的时候可以设置成 -1 不限制）
pub struct SoftdogManager {
    ut_dll: Library,
}

impl SoftdogManager {
    pub fn new(path_dll: PathBuf) -> Self {
        let path = Path::new(&path_dll);
        println!("path:{}", path.display());
        let ut_dll = unsafe { Library::new(path).unwrap() };

        Self { ut_dll }
    }
    ///模块设置 初始化调用一次
    pub fn module_set(&self, serial: c_ulong) -> SoftdogResult {
        unsafe {
            let module_set: Symbol<ModuleSet> = self.ut_dll.get(b"ModuleSet").unwrap();
            let s1 = module_set(0, serial);
            if s1 != 0 {
                let result_str = format!("{:04x}", s1);
                match ERROR_CODE.get(&result_str) {
                    Some(msg) => {
                        info!("module_set error :{}", msg);
                        return SoftdogResult {
                            status: 500,
                            msg: Some(msg.to_string()),
                            data: None,
                        };
                    }
                    None => {
                        return SoftdogResult {
                            status: 500,
                            msg: Some(result_str),
                            data: None,
                        };
                    }
                }
            }
            let s2 = module_set(1, serial);
            if s2 != 0 {
                let result_str = format!("{:04x}", s2);
                match ERROR_CODE.get(&result_str) {
                    Some(msg) => {
                        info!("module_set error :{}", msg);
                        return SoftdogResult {
                            status: 500,
                            msg: Some(msg.to_string()),
                            data: None,
                        };
                    }
                    None => {
                        return SoftdogResult {
                            status: 500,
                            msg: Some(result_str),
                            data: None,
                        };
                    }
                }
            }
        }
        SoftdogResult {
            status: 200,
            msg: Some("初始化".to_string()),
            data: None,
        }
    }
    /// 初始化锁 可以不主动调用
    pub fn init_secret(&self, serial: c_ulong) -> SoftdogResult {
        unsafe {
            let initiate_lock = self.ut_dll.get::<InitiateLock>(b"InitiateLock\0").unwrap();
            let result = initiate_lock(serial);
            if result == 0 {
                return SoftdogResult {
                    status: 200,
                    msg: Some("初始化".to_string()),
                    data: None,
                };
            }
            let result_str = format!("{:04x}", result);
            SoftdogResult {
                status: 500,
                msg: Some(ERROR_CODE.get(&result_str).unwrap().to_string()),
                data: None,
            }
        }
    }

    pub fn set_limit(&self, u_serial: u32, psz_psd: &str) -> SoftdogResult {
        unsafe {
            let c_str = CString::new(psz_psd).unwrap();
            let mut receive_buf: Vec<u8> = vec![0; 32];
            let func: Symbol<SetLimit> = self.ut_dll.get(b"SetLimit").unwrap();
            let result = func(
                receive_buf.as_mut_ptr(),
                c_str.as_ptr(),
                2,
                u_serial as c_ulong,
            );
            match result.cmp(&0) {
                std::cmp::Ordering::Equal => {
                    let lock_type = u32::from_le_bytes(receive_buf[24..28].try_into().unwrap());
                    SoftdogResult {
                        status: 200,
                        msg: Some("生成成功".to_string()),
                        data: Some(lock_type.to_string()),
                    }
                }
                _ => {
                    let result_str = format!("{:04x}", result);
                    SoftdogResult {
                        status: 500,
                        msg: Some(ERROR_CODE.get(&result_str).unwrap().to_string()),
                        data: None,
                    }
                }
            }
        }
    }
    /// 获取动态密码

    pub fn get_active_psd(
        &self,
        psz_psd: &str,        // 管理密码
        u_serial: u32,        // 序列号(通常设0)
        ul_limit_type: u32,   // 限制类型
        ul_limit: u32,        // 限制值
        u_serial_target: u32, // 目标锁序列号
        cycletime: u32,       // 有效时长
    ) -> SoftdogResult {
        let mut buffer: Vec<u8> = vec![0; 32];
        unsafe {
            // 将Rust字符串转换为C字符串
            let c_str = CString::new(psz_psd).unwrap();
            let func: Symbol<GetActivePsd> = self.ut_dll.get(b"GetActivePsd").unwrap();
            let result = func(
                c_str.as_ptr(),
                u_serial as c_ulong,
                ul_limit_type as c_ulong,
                ul_limit as c_ulong,
                u_serial_target as c_ulong,
                buffer.as_mut_ptr(),
                cycletime as c_ulong,
            );
            match result.cmp(&0) {
                std::cmp::Ordering::Equal => {
                    let mut str = "".to_string();
                    for i in 0..16 {
                        str.push_str(&format!("{:02x}", buffer[i]));
                    }
                    SoftdogResult {
                        status: 200,
                        msg: Some("生成成功".to_string()),
                        data: Some(str),
                    }
                }
                _ => {
                    let result_str = format!("{:04x}", result);
                    SoftdogResult {
                        status: 500,
                        msg: Some(ERROR_CODE.get(&result_str).unwrap().to_string()),
                        data: None,
                    }
                }
            }
        }
    }
    /// 获取锁序号
    pub fn get_sn(&self) -> Vec<c_ulong> {
        unsafe {
            let get_sn: Symbol<GetSn> = self.ut_dll.get(b"GetSn").unwrap();
            let mut sn: Vec<c_ulong> = vec![0; 10]; // 假设我们有10个序列号
            let mut count: c_ulong = sn.len() as c_ulong;
            let mut max_count: c_ulong = sn.len() as c_ulong;
            let result = get_sn(sn.as_mut_ptr(), &mut count, &mut max_count);
            if result == 0 {
                let mut arr = vec![];
                for i in sn {
                    if i > 0 {
                        arr.push(i);
                    }
                }
                arr
            } else {
                vec![]
            }
        }
    }
    /// 写入数据 1-2000(2k 空间）)
    pub fn write_first(&self, json: String, serial: c_ulong, password: CString) -> SoftdogResult {
        self.write(json, serial, 1, password)
    }
    /// 写入数据 2001-40000(38k 空间）)
    pub fn write_second(&self, json: String, serial: c_ulong, password: CString) -> SoftdogResult {
        self.write(json, serial, 2001, password)
    }
    /// 写入数据 40001-130000(130k 空间）)
    pub fn write_third(&self, json: String, serial: c_ulong, password: CString) -> SoftdogResult {
        self.write(json, serial, 40001, password)
    }

    /// 写入数据
    ///
    pub fn write(
        &self,
        str: String,
        serial: c_ulong,
        addr: c_ulong,
        password: CString,
    ) -> SoftdogResult {
        unsafe {
            let buffer = {
                let compressed = zstd::encode_all(str.as_bytes(), 3).unwrap();
                compressed
            };
            let i_buf_len: c_ulong = buffer.len() as c_ulong;
            let mut length = i_buf_len.to_string();
            {
                pad_start(&mut length, 10);
            }
            let mut contentbuffer: Vec<u8> = [length.as_bytes(), &buffer].concat().to_vec();
            let content_len: c_ulong = contentbuffer.len() as c_ulong;
            let func: Symbol<WriteLock> = self.ut_dll.get(b"WriteLock").unwrap();
            println!("{addr},{:}",password.to_str().unwrap());
            let result = func(
                addr,
                contentbuffer.as_mut_ptr() as *mut c_void,
                content_len,
                password.as_ptr() as *mut c_char,
                serial,
            );
            match result.cmp(&0) {
                std::cmp::Ordering::Equal => SoftdogResult {
                    status: 200,
                    msg: Some("写入成功".to_string()),
                    data: None,
                },
                _ => {
                    let result_str = format!("{:04x}", result);
                    SoftdogResult {
                        status: 500,
                        msg: Some(ERROR_CODE.get(&result_str).unwrap_or(&result_str).to_string()),
                        data: None,
                    }
                }
            }
        }
    }
    /// 读取数据 1-2000(2k 空间）区域)
    pub fn read_first(&self, serial: c_ulong, password: CString) -> SoftdogResult {
        self.read(serial, 1, password)
    }
    /// 读取数据 2000-40000（38k 空间）区域)
    pub fn read_second(&self, serial: c_ulong, password: CString) -> SoftdogResult {
        self.read(serial, 2001, password)
    }
    /// 读取数据 40000-130000（122k 空间）区域)
    pub fn read_third(&self, serial: c_ulong, password: CString) -> SoftdogResult {
        self.read(serial, 40001, password)
    }
    pub fn get_content_length(&self, serial: c_ulong, addr: c_ulong, password: CString) -> usize {
        println!("获取字节长度:  {addr},{:}",password.to_str().unwrap());
        unsafe {
            let read_lock: Symbol<ReadLock> = self.ut_dll.get(b"ReadLock").unwrap();
            let mut buffer: Vec<u8> = vec![0; 10]; // 要读取的缓冲区
            let read_len: c_ulong = buffer.len() as c_ulong; // 读取的数据长度
            let result = read_lock(
                addr,
                buffer.as_mut_ptr() as *mut c_void,
                read_len,
                password.as_ptr() as *mut c_char,
                serial,
            );
            if result == 0 {
                let str = String::from_utf8(buffer);
                return str.unwrap_or("0".to_string()).trim().parse().unwrap_or(0);
            }
            let result_str = format!("{:04x}", result);
            println!("读取异常错误码: {}", ERROR_CODE.get(&result_str).unwrap_or(&result_str).to_string());
            0
        }
    }
    /// 读取数据
    pub fn read(&self, serial: c_ulong, addr: c_ulong, password: CString) -> SoftdogResult {
        let content_length = self.get_content_length(serial, addr, password.clone());
        if content_length == 0 {
            return SoftdogResult {
                status: 500,
                msg: Some("空锁".to_string()),
                data: None,
            };
        }
        unsafe {
            let mut content_buffer: Vec<u8> = vec![0; content_length]; // 要读取的缓冲区
            let read_lock: Symbol<ReadLock> = self.ut_dll.get(b"ReadLock").unwrap();
            let result = read_lock(
                addr + 10,
                content_buffer.as_mut_ptr() as *mut c_void,
                content_length as c_ulong,
                password.as_ptr() as *mut c_char,
                serial,
            );
            if result == 0 {
                let decompressed = zstd::decode_all(content_buffer.as_slice()).unwrap();
                let str = String::from_utf8(decompressed).unwrap();
                return SoftdogResult {
                    status: 200,
                    msg: Some("读取成功".to_string()),
                    data: Some(str),
                };
            }

            let result_str = format!("{:04x}", result);
            SoftdogResult {
                status: 500,
                msg: Some(ERROR_CODE.get(&result_str).unwrap().to_string()),
                data: None,
            }
        }
    }
}
